package com.springboot.wisdom.user.service.impl;

import cn.dev33.satoken.stp.SaLoginModel;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.yulichang.base.MPJBaseServiceImpl;
import com.github.yulichang.query.MPJLambdaQueryWrapper;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.springboot.wisdom.common.common.RedisCache;
import com.springboot.wisdom.common.common.ResultUtil;
import com.springboot.wisdom.common.common.bean.DeleteDTO;
import com.springboot.wisdom.common.common.bean.MyResult;
import com.springboot.wisdom.common.common.bean.PageQueryDTO;
import com.springboot.wisdom.common.common.constant.LogStatusEnum;
import com.springboot.wisdom.common.common.model.JwtUserInfo;
import com.springboot.wisdom.common.util.IPUtils;
import com.springboot.wisdom.email.service.EmailService;
import com.springboot.wisdom.log.domain.vo.LogVO;
import com.springboot.wisdom.log.service.LogService;
import com.springboot.wisdom.serviceApi.system.model.entity.DeptDO;
import com.springboot.wisdom.serviceApi.system.model.entity.RoleDO;
import com.springboot.wisdom.serviceApi.user.model.dto.UserInfoDTO;
import com.springboot.wisdom.serviceApi.user.model.entity.UserDO;
import com.springboot.wisdom.serviceApi.user.model.vo.LoginUserVO;
import com.springboot.wisdom.serviceApi.user.model.vo.RegisterUserVO;
import com.springboot.wisdom.serviceApi.user.model.vo.UserTokenInfo;
import com.springboot.wisdom.serviceApi.user.model.vo.UserVO;
import com.springboot.wisdom.user.mapper.UserMapper;
import com.springboot.wisdom.user.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

@Service
@Slf4j
public class UserServiceImpl extends MPJBaseServiceImpl<UserMapper, UserDO> implements UserService {

    @Autowired
    private UserMapper userMapper;


    @Resource
    private EmailService emailService;

    @Resource
    private LogService logService;

    @Resource
    private RedisCache redisCache;

    /**
     * 员工号前缀。
     */
    private static final String userIdPrefixes = "zs_";
    private static final String prefixes = userIdPrefixes;

    @Override
    public MyResult<UserTokenInfo> userPassLogin(LoginUserVO loginData, HttpServletRequest request) {
        UserInfoDTO userInfoDTO = userMapper.selectJoinOne(UserInfoDTO.class, new MPJLambdaWrapper<UserDO>()
                .eq(UserDO::getUsername, loginData.getUser())
                .eq(UserDO::getPassword, loginData.getPassword()));
        if (userInfoDTO == null) {
            return ResultUtil.error("用户名或密码错误！");
        }
        String userId = userInfoDTO.getUserId();
        JwtUserInfo jwtUserInfo = new JwtUserInfo();
        jwtUserInfo.setUserId(userId);
        jwtUserInfo.setUserName(userInfoDTO.getUsername());
        jwtUserInfo.setDepartmentId(userInfoDTO.getDepartmentId());
        jwtUserInfo.setDepartmentName(userInfoDTO.getDepartmentName());
        jwtUserInfo.setRoleId(userInfoDTO.getRoleId());
        jwtUserInfo.setRoleName(userInfoDTO.getRoleName());
        String jsonStr = JSONUtil.toJsonStr(jwtUserInfo);

        // `SaLoginModel`为登录参数Model，其有诸多参数决定登录时的各种逻辑，【记住我模式】 例如：
        StpUtil.login(prefixes + userId, new SaLoginModel()
                        .setDevice(StpUtil.getLoginDevice())                // 此次登录的客户端设备类型, 用于[同端互斥登录]时指定此次登录的设备类型
                        .setIsLastingCookie(true)        // 是否为持久Cookie（临时Cookie在浏览器关闭时会自动删除，持久Cookie在重新打开后依然存在）
                        .setTimeout(60 * 60 * 24 * 7)    // 指定此次登录token的有效期, 单位:秒 （如未指定，自动取全局配置的 timeout 值）
//                .setToken("xxxx-xxxx-xxxx-xxxx") // 预定此次登录的生成的Token
                        .setIsWriteHeader(true)         // 是否在登录后将 Token 写入到响应头
        );

        log.debug("IPUtils.getIpAddr(request) = " + IPUtils.getIpAddr(request));
        logService.addInfo(new LogVO(LogStatusEnum.LOGIN, "登录成功！", IPUtils.getIpAddr(request)));

        UserTokenInfo userTokenInfo = new UserTokenInfo(userInfoDTO, StpUtil.getTokenValue());
        log.info("登录返回信息1：{}", userTokenInfo.toString());

        return ResultUtil.success(userTokenInfo);
    }

    @Override
    public MyResult<UserInfoDTO> register(RegisterUserVO registerUserVO, HttpServletRequest request) {
        Long isUsername = userMapper.selectJoinCount(new MPJLambdaQueryWrapper<UserDO>().eq(UserDO::getUsername, registerUserVO.getUsername()));
        if (isUsername > 0) {
            return ResultUtil.error("用户名称已存在!");
        }
        Long isAccount = userMapper.selectJoinCount(new MPJLambdaQueryWrapper<UserDO>().eq(UserDO::getUserAccount, registerUserVO.getUserAccount()));
        if (isAccount > 0) {
            return ResultUtil.error("账号已存在!");
        }
        // 邮箱
        MyResult<Boolean> isEmailCode = emailService.checkEmail(registerUserVO.getEmail(), registerUserVO.getEmailCode());
        if (!isEmailCode.isResultStatus()) {
            return ResultUtil.error(isEmailCode.getErrorMessage());
        }

        UserDO userDO = new UserDO(null, registerUserVO.getUsername(), registerUserVO.getUserAccount()
                , userIdPrefixes + 11, null, registerUserVO.getPassword()
                , null, registerUserVO.getEmail(), registerUserVO.getPhone(), null
                , null, null, null, DateTime.now(), IPUtils.getIpAddr(request));
        int insert = userMapper.insert(userDO);
        UserInfoDTO userInfoDTO = new UserInfoDTO();
        if (insert > 0) {
            userInfoDTO.setUserId(userDO.getUserId());
            userInfoDTO.setUsername(userDO.getUsername());
            userInfoDTO.setUserAccount(userDO.getUserAccount());
            userInfoDTO.setUserNo(userDO.getUserNo());
            userInfoDTO.setUserIdCard(userDO.getUserIdCard());
            userInfoDTO.setEmail(userDO.getEmail());
            userInfoDTO.setPhone(userDO.getPhone());
            userInfoDTO.setDepartmentId(userDO.getDeptId());
//            userInfoDTO.setDepartmentName(userDO.getDepartmentName());
            userInfoDTO.setRoleId(userDO.getRoleId());
//            userInfoDTO.setRoleName(userDO.getRoleName());
            userInfoDTO.setPermissions(userDO.getPermissions());
            logService.addInfo(new LogVO(userDO.getUserId(), LogStatusEnum.REGISTER, "注册成功！", ""));

        }
        return insert > 0 ? ResultUtil.success(userInfoDTO) : ResultUtil.error("注册失败！");
    }

    @Override
    public MyResult<String> logout(HttpServletRequest request) {
        // StpUtil.logout() 在未登录时也是可以调用成功的，
        // 也就是说，无论客户端有没有登录，执行完 StpUtil.logout() 后，都会处于未登录状态
        System.out.println("当前是否处于登录状态：" + StpUtil.isLogin());

        // 退出登录会清除三个地方的数据：
        // 		1、Redis中保存的 Token 信息
        // 		2、当前请求上下文中保存的 Token 信息
        // 		3、Cookie 中保存的 Token 信息（如果未使用Cookie模式则不会清除）
        logService.addInfo(new LogVO(LogStatusEnum.LOGOUT, "退出登录！", IPUtils.getIpAddr(request)));
        StpUtil.logout();
        // 返回给前端
        return ResultUtil.success("退出登录成功");
    }

    /**
     * 修改邮箱。【业务操作，非数据库操作，依赖数据库操作的 修改邮箱】
     *
     * @param oldEmail
     * @param oldCode
     * @param newEmail
     * @param newCode
     * @return
     */
    @Override
    public MyResult<String> editEmail(String oldEmail, String oldCode, String newEmail, String newCode) {

        if (!emailService.checkEmail(oldEmail, oldCode).isResultStatus()) {
            return ResultUtil.error("旧邮箱验证码有误！请重新输入！");
        }
        if (!emailService.checkEmail(newEmail, newCode).isResultStatus()) {
            return ResultUtil.error("新邮箱验证码有误！请重新输入！");
        }

        MyResult<String> stringMyResult = this.changeEmail(StpUtil.getLoginId().toString().split("_")[1], oldEmail, newEmail);

        if (stringMyResult != null && stringMyResult.isResultStatus()) {
            redisCache.deleteObject(oldEmail);
            redisCache.deleteObject(newEmail);

            return ResultUtil.success("邮箱更改成功！");
        }
        return ResultUtil.error(stringMyResult == null ? "邮箱更改失败！请重试！" : stringMyResult.getErrorMessage());
    }


    @Override
    public MyResult<Page<UserVO>> getInfoPageBy(PageQueryDTO pageQueryDTO, UserVO userVO) {

        String userId = this.getLoginUserId();
        System.out.println("userId = " + userId);

        // 连表求总数。s
        MPJLambdaWrapper<UserDO> countWrapper = new MPJLambdaWrapper<UserDO>()
                .likeIfExists(UserDO::getUserAccount, userVO.getUserAccount())
                .likeIfExists(UserDO::getUsername, userVO.getUsername())
                .likeIfExists(UserDO::getEmail, userVO.getEmail())
                .likeIfExists(UserDO::getPhone, userVO.getPhone());
        Long total = userMapper.selectJoinCount(countWrapper);

        // 连表分页查询。
        MPJLambdaWrapper<UserDO> lambdaWrapper = new MPJLambdaWrapper<UserDO>().selectAll(UserDO.class)
                .selectAs(RoleDO::getRoleName, UserVO::getRoleName)
                .selectAs(DeptDO::getDeptName, UserVO::getDeptName)
                .selectAs(RoleDO::getRoleType, UserVO::getRoleType)
                .leftJoin(RoleDO.class, RoleDO::getRoleId, UserDO::getRoleId)
                .leftJoin(DeptDO.class, DeptDO::getDeptId, UserDO::getDeptId)
                .likeIfExists(UserDO::getUserAccount, userVO.getUserAccount())
                .likeIfExists(UserDO::getUsername, userVO.getUsername())
                .likeIfExists(UserDO::getEmail, userVO.getEmail())
                .likeIfExists(UserDO::getPhone, userVO.getPhone());

        Page<UserVO> userVOIPage = userMapper.selectJoinPage(
                pageQueryDTO.toPage(pageQueryDTO.getCurrent(), pageQueryDTO.getSize(), total, false)
                , UserVO.class, lambdaWrapper);
        System.out.println(userVOIPage.getRecords());//获取分页记录
        System.out.println(userVOIPage.getPages());//总页数
        System.out.println(userVOIPage.getTotal());//总记录数
        System.out.println(userVOIPage.hasPrevious());//是否有上一页
        System.out.println(userVOIPage.hasNext());//是否有下一页
        return ResultUtil.success(userVOIPage);
    }

    @Override
    public MyResult<String> rePassword(String id, HttpServletRequest request) {
        UserDO userDO = new UserDO();
        userDO.setUserId(id);
        userDO.setPassword("123456");
        int result = userMapper.updateById(userDO);
        if (result > 0) {
            logService.addInfo(new LogVO(LogStatusEnum.RE_PASSWORD, "账号 " + userDO.getUsername() + " 密码重置成功！", IPUtils.getIpAddr(request)));
        }
        return result > 0 ? ResultUtil.success("密码重置成功！") : ResultUtil.error("密码重置失败！");
    }

    @Override
    public MyResult<String> setStatus(String id, HttpServletRequest request) {
//        UserDO userDO = userMapper.selectById(id);
//        if (userDO == null) {
//            return ResultUtil.error("账号不存在！！");
//        }
//        userDO.setUserId(id);
//        // 0：未禁用。1：禁用。
//        userDO.setStatus(userDO.getStatus() == 0 ? 1 : 0);
//        int result = userMapper.updateById(userDO);
//        if (result > 0) {
//            logService.addInfo(new LogVO(LogTypeEnum.ACCOUNT_STATUS
//                    , "账号 " + userDO.getUsername() + " 状态【" + (userDO.getStatus() == 0 ? "解除禁用" : "禁用") + "】！"
//                    , IPUtils.getIpAddr(request)));
//        }
//        return result > 0 ? ResultUtil.success("账号状态更改成功！") : ResultUtil.error("账号状态更改失败！");
        return null;
    }

    @Override
    public MyResult<String> deleteInfo(String id, HttpServletRequest request) {
        UserDO userDO = userMapper.selectById(id);
        if (userDO == null) {
            return ResultUtil.error("账号已被注销！");
        }
        int result = userMapper.deleteById(id);
        if (result > 0) {
            logService.addInfo(new LogVO(LogStatusEnum.ACCOUNT_DELETE, "注销账号 " + userDO.getUsername() + " 成功！", IPUtils.getIpAddr(request)));
        }
        return result > 0 ? ResultUtil.success("注销账号成功！") : ResultUtil.error("注销账号失败！");
    }


    /**
     * 查看邮箱是否注册。
     *
     * @param email 检查的邮箱。
     * @return true：存在。     false：不存在。
     */
    @Override
    public Boolean isEmail(String email) {
        Long isEmail = userMapper.selectCount(new LambdaQueryWrapper<UserDO>().eq(UserDO::getEmail, email));
        return isEmail > 0;
    }

    /**
     * 获取当前登录的用户ID
     *
     * @return
     */
    private String getLoginUserId() {
        return StpUtil.getLoginId().toString().split("_")[1];
    }


    @Override
    public MyResult<String> changeName(String userId, String name) {
        UserDO userDO = userMapper.selectOne(new LambdaQueryWrapper<UserDO>().eq(UserDO::getUserId, userId));
        if (userDO == null) {
            return ResultUtil.error("账号已下线！请重新登录！");
        }
        userDO.setUsername(name);
        int result = userMapper.updateById(userDO);
        if (result > 0) {
            logService.addInfo(new LogVO(LogStatusEnum.UPDATE_INFO_NAME, "名称更改成功！", ""));
        }
        return result > 0 ? ResultUtil.success("名称更改成功！") : ResultUtil.error("名称更改失败！");
    }

    @Override
    public MyResult<String> changePassword(String userId, String oldPassword, String newPassword) {
        UserDO user = userMapper.selectOne(new LambdaQueryWrapper<UserDO>().eq(UserDO::getUserId, userId).eq(UserDO::getPassword, oldPassword));
        if (user == null) {
            return ResultUtil.error("旧密码错误！");
        }
        user.setPassword(newPassword);
        int result = userMapper.updateById(user);
        if (result > 0) {
            logService.addInfo(new LogVO(LogStatusEnum.UPDATE_INFO_PASSWORD, "密码更改成功！", ""));
        }
        return result > 0 ? ResultUtil.success("密码更改成功！") : ResultUtil.error("修改失败！");
    }

    @Override
    public MyResult<String> changePhone(String userId, String newPhone) {
        UserDO user = userMapper.selectOne(new LambdaQueryWrapper<UserDO>().eq(UserDO::getUserId, userId));
        if (user == null) {
            return ResultUtil.error("账号已下线！请重新登录！");
        }
        user.setPhone(newPhone);
        int result = userMapper.updateById(user);
        if (result > 0) {
            logService.addInfo(new LogVO(LogStatusEnum.UPDATE_INFO_PHONE, "手机号更改成功！", ""));
        }
        return result > 0 ? ResultUtil.success("手机号更改成功！") : ResultUtil.error("手机号更改失败！");

    }

    @Override
    public MyResult<String> changeAvatarUrl(String userId, String avatarUrl) {
        UserDO user = userMapper.selectOne(new LambdaQueryWrapper<UserDO>().eq(UserDO::getUserId, userId));
        if (user == null) {
            return ResultUtil.error("账号已下线！请重新登录！");
        }
        user.setAvatarUrl(avatarUrl);
        int result = userMapper.updateById(user);
        if (result > 0) {
            logService.addInfo(new LogVO(LogStatusEnum.UPDATE_INFO_AVATAR_URL, "头像更改成功！", ""));
        }
        return result > 0 ? ResultUtil.success("头像更改成功！") : ResultUtil.error("头像更改失败！");

    }


    /******************************************** 没用到  ***********************************************************/
    @Override
    public MyResult<String> addInfo(UserVO userVO) {
        UserDO user = userMapper.selectOne(new LambdaQueryWrapper<UserDO>().eq(UserDO::getUserAccount, userVO.getUserAccount()));
        if (user != null) {
            return ResultUtil.error(userVO.getUserAccount() + "已存在！请勿重复添加！");
        }
        // 默认值。
        userVO.setUserId(null);
        // 默认密码。
        userVO.setPassword(userVO.getUserAccount() + "123456");
        userVO.setCreateTime(null);
        userVO.setUpdateTime(null);
//        userVO.setRole(RoleEnum.STUDENT.getValue());
        return userMapper.insert(userVO) > 0 ? ResultUtil.success("添加成功！") : ResultUtil.error("添加失败！");
    }

    @Override
    public MyResult<String> delInfo(String userId) {
        return userMapper.deleteById(userId) > 0 ? ResultUtil.success("删除成功！") : ResultUtil.error("删除失败，请重新操作！");
    }

    @Override
    public MyResult<String> delInfo(DeleteDTO<String> deleteIds) {
        int successNum = userMapper.deleteByIds(deleteIds.getIdList());
        return successNum > 0 ? ResultUtil.success("删除成功！共删除：" + successNum + "条") : ResultUtil.error("删除失败，请重新操作！");
    }


    @Override
    public MyResult<UserVO> getUserById(String userId) {
        UserVO userVO = userMapper.selectJoinOne(UserVO.class, new MPJLambdaWrapper<UserDO>()
                .selectAll(UserDO.class)
                .selectAs(RoleDO::getRoleName, UserVO::getRoleName)
                .selectAs(RoleDO::getRoleType, UserVO::getRoleType)
                .leftJoin(RoleDO.class, RoleDO::getRoleId, UserDO::getRoleId)
                .eq(UserDO::getUserId, userId));
        return ResultUtil.success(userVO);
    }

    @Override
    public MyResult<UserVO> getUserByUsername(String username) {
        UserVO userVO = userMapper.selectJoinOne(UserVO.class, new MPJLambdaWrapper<UserDO>().eq(UserDO::getUsername, username));
//        System.out.println("userVO = " + userVO);
        return userVO != null ? ResultUtil.success(userVO) : ResultUtil.error("用户不存在！");
    }

    @Override
    public MyResult<IPage<UserVO>> getUserInfoPageBy(PageQueryDTO pageQueryDTO, UserVO userVO) {
//        // 连表求总数。s
//        MPJLambdaWrapper<UserDO> countWarpper = new MPJLambdaWrapper<UserDO>()
//                .leftJoin(ClassInfoDO.class, ClassInfoDO::getTeacherId, "t", UserDO::getUserId)
//                .leftJoin(UserDO.class, "c", UserDO::getClassId, ClassInfoDO::getClassId)
//                .eq("t", UserDO::getUserId, StpUtil.getLoginId().toString().split("_")[1])
//                .likeIfExists("c", UserDO::getName, userVO.getName())
//                .eqIfExists(ClassInfoDO::getClassId, userVO.getClassId())
//                .isNotNull("c", UserDO::getUserId)
//                .likeIfExists("c", UserDO::getUsername, userVO.getUsername())
//                .likeIfExists(ClassInfoDO::getClassName, userVO.getClassName());
//        Long total = userMapper.selectJoinCount(countWarpper);
//
//        // 连表分页查询。
//        MPJLambdaWrapper<UserDO> lambdaWrapper = new MPJLambdaWrapper<UserDO>()
//                .selectAll(ClassInfoDO.class)
//                .selectAll(UserDO.class, "c")
//                .leftJoin(ClassInfoDO.class, ClassInfoDO::getTeacherId, UserDO::getUserId)
//                .leftJoin(UserDO.class, "c", UserDO::getClassId, ClassInfoDO::getClassId)
//                .eq(UserDO::getUserId, StpUtil.getLoginId().toString().split("_")[1])
//                .likeIfExists("c", UserDO::getName, userVO.getName())
//                .eqIfExists(ClassInfoDO::getClassId, userVO.getClassId())
//                .isNotNull("c", UserDO::getUserId)
//                .likeIfExists("c", UserDO::getUsername, userVO.getUsername())
//                .likeIfExists(ClassInfoDO::getClassName, userVO.getClassName())
//                .orderByAsc("c", UserDO::getUserId);
//
//        Page<UserVO> userVOIPage = userMapper.selectJoinPage(
//                pageQueryDTO.toPage(pageQueryDTO.getCurrent(), pageQueryDTO.getSize(), total, false)
//                , UserVO.class
//                , lambdaWrapper);
////        System.out.println(userVOIPage.getRecords());//获取分页记录
////        System.out.println(userVOIPage.getPages());//总页数
////        System.out.println(userVOIPage.getTotal());//总记录数
////        System.out.println(userVOIPage.hasPrevious());//是否有上一页
////        System.out.println(userVOIPage.hasNext());//是否有下一页
//        return ResultUtil.success(userVOIPage);
        return null;
    }

    @Override
    public MyResult<String> changeInfo(UserVO userVO) {
//        userVO.setRole(null);
//        userVO.setRegisterDate(null);
        return userMapper.updateById(userVO) > 0 ? ResultUtil.success("信息更改成功！") : ResultUtil.error("信息更改失败！");
    }


    /**
     * 修改邮箱。【数据库操作】
     *
     * @param userId
     * @param oldEmail
     * @param newEmail
     * @return
     */
    public MyResult<String> changeEmail(String userId, String oldEmail, String newEmail) {
        UserDO user = userMapper.selectOne(new LambdaQueryWrapper<UserDO>().eq(UserDO::getUserId, userId).eq(UserDO::getEmail, oldEmail));
        if (user == null) {
            return ResultUtil.error("旧邮箱错误！请重新输入！");
        }
        user.setEmail(newEmail);
        return userMapper.updateById(user) > 0 ? ResultUtil.success("邮箱更改成功！") : ResultUtil.error("邮箱更改失败！");

    }

}
